<template>
  <div ref="wrapperRef">
    <div ref="spinRef" :style="spinStyle" v-loading="loading" :loading-tip="loadingTip">
      <slot></slot>
    </div>
  </div>
</template>
<script setup lang="ts">
  import { useMutationObserver } from '@vueuse/core'
  import type { CSSProperties } from 'vue'
  import { computed, nextTick, onMounted, onUnmounted, ref, unref, watch, watchEffect } from 'vue'

  defineOptions({
    inheritAttrs: false
  })

  const props = defineProps({
    loading: { type: Boolean },
    useWrapper: { type: Boolean, default: true },
    modalHeaderHeight: { type: Number, default: 57 },
    modalFooterHeight: { type: Number, default: 74 },
    minHeight: { type: Number, default: 200 },
    height: { type: Number },
    footerOffset: { type: Number, default: 0 },
    visible: { type: Boolean },
    fullScreen: { type: Boolean },
    loadingTip: { type: String }
  })

  const emit = defineEmits(['height-change', 'ext-height'])
  const wrapperRef = ref<ComponentRef>(null)
  const spinRef = ref<ElRef>(null)
  const realHeightRef = ref(0)
  const minRealHeightRef = ref(0)

  let realHeight = 0

  let stopElResizeFn: Fn = () => {}

  useMutationObserver(
    spinRef,
    () => {
      setModalHeight()
    },
    {
      attributes: true,
      subtree: true
    }
  )

  const spinStyle = computed((): CSSProperties => {
    return {
      minHeight: `${props.minHeight}px`,
      [props.fullScreen ? 'height' : 'maxHeight']: `${unref(realHeightRef)}px`
    }
  })

  watchEffect(() => {
    props.useWrapper && setModalHeight()
  })

  watch(
    () => props.fullScreen,
    (v) => {
      setModalHeight()
      if (!v) {
        realHeightRef.value = minRealHeightRef.value
      } else {
        minRealHeightRef.value = realHeightRef.value
      }
    }
  )

  onMounted(() => {
    const { modalHeaderHeight, modalFooterHeight } = props
    emit('ext-height', modalHeaderHeight + modalFooterHeight)
  })

  onUnmounted(() => {
    stopElResizeFn && stopElResizeFn()
  })

  // async function scrollTop() {
  //   nextTick(() => {
  //     const wrapperRefDom = unref(wrapperRef)
  //     if (!wrapperRefDom) return
  //     ;(wrapperRefDom as any)?.scrollTo?.(0)
  //   })
  // }

  async function setModalHeight() {
    // 解决在弹窗关闭的时候监听还存在,导致再次打开弹窗没有高度
    // 加上这个,就必须在使用的时候传递父级的visible
    if (!props.visible) return
    const wrapperRefDom = unref(wrapperRef)
    if (!wrapperRefDom) return

    const bodyDom = wrapperRefDom.$el.parentElement
    if (!bodyDom) return
    bodyDom.style.padding = '0'
    await nextTick()

    try {
      const modalDom = bodyDom.parentElement && bodyDom.parentElement.parentElement
      if (!modalDom) return

      const modalRect = getComputedStyle(modalDom as Element).top
      const modalTop = Number.parseInt(modalRect)
      let maxHeight =
        window.innerHeight -
        modalTop * 2 +
        (props.footerOffset! || 0) -
        props.modalFooterHeight -
        props.modalHeaderHeight

      // 距离顶部过进会出现滚动条
      if (modalTop < 40) {
        maxHeight -= 26
      }
      await nextTick()
      const spinEl = unref(spinRef)

      if (!spinEl) return
      await nextTick()
      // if (!realHeight) {
      realHeight = spinEl.scrollHeight
      // }

      if (props.fullScreen) {
        realHeightRef.value = window.innerHeight - props.modalFooterHeight - props.modalHeaderHeight - 28
      } else {
        realHeightRef.value = props.height ? props.height : realHeight > maxHeight ? maxHeight : realHeight
      }
      emit('height-change', unref(realHeightRef))
    } catch (error) {
      console.error(error)
    }
  }
</script>
